#include "stdafx.h"
#include "CScrLanguage.h"
#include "CScriptEngine.h"
#include "CParser.h"

int CControlStructs::s_nNumControlStructs;
CControlStruct * CControlStructs::s_pFirst;
CControlStruct * CControlStructs::s_pLast;

int CSyntax::s_nNumExtendedTypes;
bool CSyntax::s_bDefaultsLoaded = false;
CList<CTypeBase>			CSyntax::s_TypeMap;
CLListEx<CTypeBase*>		CSyntax::s_TypeList;

// Parsable command names for definitions
const CSyntax::sParseNames CSyntax::s_pParseOpcodeArray[] = {
	{"IF",					SCRIPT_IF},
	//{"IFNOT",				SCRIPT_IFNOT},
	{"ANDOR",				SCRIPT_ANDOR},
	{"ELSE",				SCRIPT_ELSE},
	{"ENDIF",				SCRIPT_ENDIF},
	{"GOTO",				SCRIPT_GOTO},
	{"ELSE_GOTO",			SCRIPT_ELSE_GOTO},
	{"NAME",				SCRIPT_NAME},
	{"END",					SCRIPT_END},
	{"REPEAT",				SCRIPT_REPEAT},
	{"ENDREPEAT",			SCRIPT_ENDREPEAT},
	{"WHILE",				SCRIPT_WHILE},
	{"WHILENOT",			SCRIPT_WHILENOT},
	{"ENDWHILE",			SCRIPT_ENDWHILE},
	{"START",				SCRIPT_START},
	{"CASE",				SCRIPT_CASE},
	{"WHEN",				SCRIPT_WHEN},
	{"ENDCASE",				SCRIPT_ENDCASE},
};

// Directives
const CSyntax::sDirectives CSyntax::s_pDirectivesArray[] = {
	{"PUSHCFG",				DIRECTIVE_PUSH_CONFIG},
	{"POPCFG",				DIRECTIVE_POP_CONFIG},
	{"INCLUDE",				DIRECTIVE_INCLUDE},
	{"IMPORT",				DIRECTIVE_IMPORT},
	{"CONST",				DIRECTIVE_CONST_BEGIN},
	{"ENDCONST",			DIRECTIVE_CONST_END},
	{"HEX",					DIRECTIVE_HEX_BEGIN},
	{"ENDHEX",				DIRECTIVE_HEX_END},
	{"ASM",					DIRECTIVE_ASM_BEGIN},
	{"ENDASM",				DIRECTIVE_ASM_END},
	{"DEFINE",				DIRECTIVE_DEFINE},
	{"UNDEF",				DIRECTIVE_UNDEF},
	{"IF",					DIRECTIVE_IF},
	{"ELSE",				DIRECTIVE_ELSE},
	{"ENDIF",				DIRECTIVE_ENDIF},
	{"ERROR",				DIRECTIVE_ERROR},
	{"WARNING",				DIRECTIVE_WARNING},
	{"REGISTER_COMMAND",	DIRECTIVE_REGISTER_COMMAND},
	{"REGISTER_OPERATOR",	DIRECTIVE_REGISTER_OPERATOR},
	{"LOAD_TYPES",			DIRECTIVE_LOAD_TYPES},
	{"REGISTER_TYPE",		DIRECTIVE_REGISTER_TYPE},
	{"REGISTER_VAR",		DIRECTIVE_REGISTER_VAR},
	{"HEADER",				DIRECTIVE_HEADER},
	{"ENDHEADER",			DIRECTIVE_ENDHEADER},
	{"CONSOLE",				DIRECTIVE_CONSOLE},
	{"ENDCONSOLE",			DIRECTIVE_ENDCONSOLE},
	{"FUNCTION",			DIRECTIVE_FUNCTION},
	{"ENDFUNCTION",			DIRECTIVE_ENDFUNCTION},
	{"EACH",				DIRECTIVE_EACH},
	{"ENDEACH",				DIRECTIVE_ENDEACH},
};

// Stuff...
CSyntax::sDefinitions CSyntax::s_pDefinitions[] = {
	{false, "MAX_CONDITIONS"},
	{false, "MAX_VAR_INDEX"},
	{false, "NUM_BYTES_IN_ARRAY_FLAG"},
	{false, "MAIN_VAR_BLOCK_OFFSET"},
	{false, "LOGICAL_AND"},
	{false, "LOGICAL_OR"},
	{false, "LOGICAL_NOT"},
	{false, "PREFIX_LOGICAL_AND"},
	{false, "PREFIX_LOGICAL_OR"},
	{false, "PREFIX_LOGICAL_NOT"},
};

CSyntax::sConstructs CSyntax::s_pConstructs[];

// Save us some time
const int		&MAX_CONDITIONS				= CSyntax::s_pDefinitions[DEF_MAX_CONDITIONS].nValue.i;
const int		&MAX_VAR_INDEX				= CSyntax::s_pDefinitions[DEF_MAX_VAR_INDEX].nValue.i;
const DWORD		&NUM_BYTES_IN_ARRAY_FLAG	= CSyntax::s_pDefinitions[DEF_NUM_BYTES_IN_ARRAY_FLAG].nValue.dw;
const DWORD		&MAIN_VAR_BLOCK_OFFSET		= CSyntax::s_pDefinitions[DEF_MAIN_VAR_BLOCK_OFFSET].nValue.dw;
const int		&LOGICAL_AND				= CSyntax::s_pDefinitions[DEF_LOGICAL_AND].nValue.i;
const int		&LOGICAL_OR					= CSyntax::s_pDefinitions[DEF_LOGICAL_OR].nValue.i;
const int		&LOGICAL_NOT				= CSyntax::s_pDefinitions[DEF_LOGICAL_NOT].nValue.i;
const int		&PREFIX_LOGICAL_AND			= CSyntax::s_pDefinitions[DEF_PREFIX_LOGICAL_AND].nValue.i;
const int		&PREFIX_LOGICAL_OR			= CSyntax::s_pDefinitions[DEF_PREFIX_LOGICAL_OR].nValue.i;
const int		&PREFIX_LOGICAL_NOT			= CSyntax::s_pDefinitions[DEF_PREFIX_LOGICAL_NOT].nValue.i;

const char	*	szSCR_TRUE					= CSyntax::s_pConstructs[SCR_TRUE].szName;
const char	*	szSCR_FALSE					= CSyntax::s_pConstructs[SCR_FALSE].szName;
const char	*	szSCR_AND					= CSyntax::s_pConstructs[SCR_AND].szName;
const char	*	szSCR_OR					= CSyntax::s_pConstructs[SCR_OR].szName;
const char	*	szSCR_NOT					= CSyntax::s_pConstructs[SCR_NOT].szName;
const char	*	szSCR_BREAK					= CSyntax::s_pConstructs[SCR_BREAK].szName;
const char	*	szSCR_CONTINUE				= CSyntax::s_pConstructs[SCR_CONTINUE].szName;
const char	*	szSCR_IF					= CSyntax::s_pConstructs[SCR_IF].szName;
const char	*	szSCR_ENDIF					= CSyntax::s_pConstructs[SCR_ENDIF].szName;
const char	*	szSCR_WHILE					= CSyntax::s_pConstructs[SCR_WHILE].szName;
const char	*	szSCR_ENDWHILE				= CSyntax::s_pConstructs[SCR_ENDWHILE].szName;
const char	*	szSCR_REPEAT				= CSyntax::s_pConstructs[SCR_REPEAT].szName;
const char	*	szSCR_ENDREPEAT				= CSyntax::s_pConstructs[SCR_ENDREPEAT].szName;
const char	*	szSCR_ELSE					= CSyntax::s_pConstructs[SCR_ELSE].szName;
const char	*	szSCR_CASE					= CSyntax::s_pConstructs[SCR_CASE].szName;
const char	*	szSCR_WHEN					= CSyntax::s_pConstructs[SCR_WHEN].szName;
const char	*	szSCR_ENDCASE				= CSyntax::s_pConstructs[SCR_ENDCASE].szName;
const char	*	szSCR_MISSION_START			= CSyntax::s_pConstructs[SCR_MISSION_START].szName;

// Definitions of built-in types
const sTypeNames CSyntax::s_pTypeNames[] = {
/* Name (for output)			'Param Type' ID				ID (for input)		Pseudo-type?		*/
	{"NONE",					PT_NONE,					"0",				true,				TOKEN_VALUE},
	{"INT",						PT_INT,						"i",				false,				TOKEN_VALUE},
	{"FLOAT",					PT_FLOAT,					"f",				false,				TOKEN_VALUE},
	{"CONST",					PT_CONST,					"c",				true,				TOKEN_CONSTANT},
	{"TEXT_LABEL",				PT_TEXT_LABEL,				"t",				false,				TOKEN_STRING},
	{"STRING",					PT_STRING,					"s",				false,				TOKEN_STRING},
	{"VAR",						PT_VAR,						"v",				false,				TOKEN_VAR},
	{"VAR_INT",					PT_VAR_INT,					"vi",				false,				TOKEN_VAR},
	{"VAR_FLOAT",				PT_VAR_FLOAT,				"vf",				false,				TOKEN_VAR},
	{"VAR_TEXT_LABEL",			PT_VAR_TEXT_LABEL,			"vt",				false,				TOKEN_VAR},
	{"VAR_STRING",				PT_VAR_STRING,				"vs",				false,				TOKEN_VAR},
	{"LVAR",					PT_LVAR,					"l",				false,				TOKEN_VAR},
	{"LVAR_INT",				PT_LVAR_INT,				"li",				false,				TOKEN_VAR},
	{"LVAR_FLOAT",				PT_LVAR_FLOAT,				"lf",				false,				TOKEN_VAR},
	{"LVAR_TEXT_LABEL",			PT_LVAR_TEXT_LABEL,			"lt",				false,				TOKEN_VAR},
	{"LVAR_STRING",				PT_LVAR_STRING,				"ls",				false,				TOKEN_VAR},
	{"VAR_ARRAY",				PT_VAR_ARRAY,				"va",				false,				TOKEN_VAR},
	{"VAR_INT_ARRAY",			PT_VAR_INT_ARRAY,			"via",				false,				TOKEN_VAR},
	{"VAR_FLOAT_ARRAY",			PT_VAR_FLOAT_ARRAY,			"vfa",				false,				TOKEN_VAR},
	{"VAR_TEXT_LABEL_ARRAY",	PT_VAR_TEXT_LABEL_ARRAY,	"vta",				false,				TOKEN_VAR},
	{"VAR_STRING_ARRAY",		PT_VAR_STRING_ARRAY,		"vsa",				false,				TOKEN_VAR},
	{"LVAR_ARRAY",				PT_LVAR_ARRAY,				"la",				false,				TOKEN_VAR},
	{"LVAR_INT_ARRAY",			PT_LVAR_INT_ARRAY,			"lia",				false,				TOKEN_VAR},
	{"LVAR_FLOAT_ARRAY",		PT_LVAR_FLOAT_ARRAY,		"lfa",				false,				TOKEN_VAR},
	{"LVAR_TEXT_LABEL_ARRAY",	PT_LVAR_TEXT_LABEL_ARRAY,	"lta",				false,				TOKEN_VAR},
	{"LVAR_STRING_ARRAY",		PT_LVAR_STRING_ARRAY,		"lsa",				false,				TOKEN_VAR},

	// Not really implemented (perhaps could be used when casting is implemented to cast INT's to variable indexes)
	{"VAR_CONST",				PT_VAR_CONST,				"vc",				true,				TOKEN_VAR},
	{"LVAR_CONST",				PT_LVAR_CONST,				"lc",				true,				TOKEN_VAR},
	{"VAR_CONST_ARRAY",			PT_VAR_CONST_ARRAY,			"vca",				true,				TOKEN_VAR},
	{"LVAR_CONST_ARRAY",		PT_LVAR_CONST_ARRAY,		"lca",				true,				TOKEN_VAR},

	// End of the line
	{NULL,						PT_NONE,					NULL,				false,				TOKEN_NONE},
};
CType						*	CSyntax::s_pTypes[] = {nullptr};

// Definitions of built-in extended types
const sExtendedTypeNames CSyntax::s_pExtendedTypeNames[] = {
	// p marks a label pointer in definitions - if we encounter it we look for a label - if we don't find one we create one
	{"LABEL",					TYPE_INT,					ET_LABEL,			"p",				TOKEN_LABEL},
	// m marks a model constant in definitions - if we encounter it look for a model constant - if not, any CONST (unless we're being strict)
	{"MODEL",					TYPE_INT,					ET_MODEL,			"m",				TOKEN_MODEL},
	// ye've gone too far...
	{NULL,						TYPE_NONE,					ET_NONE,			NULL,				TOKEN_NONE},
};
CExtendedType				*	CSyntax::s_pExtendedTypes[] = {nullptr};

// Basic type conditions for translations in types.def
const sTypeCondition CSyntax::s_TypeConditions[] = {
	// only one translation for "NONE"
	{PT_NONE,					{TRANSLATE_COND_NONE}},
	// for most things, just the size of data we need to write
	{PT_INT,					{TRANSLATE_COND_SIZEOF_VAL}},
	{PT_FLOAT,					{TRANSLATE_COND_SIZEOF_VAL}},
	{PT_CONST,					{TRANSLATE_COND_SIZEOF_VAL}},
	{PT_TEXT_LABEL,				{TRANSLATE_COND_STRLEN_STR}},
	{PT_STRING,					{TRANSLATE_COND_STRLEN_STR}},
	// *new* in case we're using a non-array var as an array and translations are setup to support it, pass the array index
	{PT_VAR,					{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR}},
	{PT_VAR_INT,				{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR}},
	{PT_VAR_FLOAT,				{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR}},
	{PT_VAR_TEXT_LABEL,			{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR}},
	{PT_VAR_STRING,				{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR}},
	{PT_LVAR,					{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR}},
	{PT_LVAR_INT,				{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR}},
	{PT_LVAR_FLOAT,				{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR}},
	{PT_LVAR_TEXT_LABEL,		{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR}},
	{PT_LVAR_STRING,			{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR}},
	// for arrays, pass the size of the array var index, the size of the index var index and the size of the array
	{PT_VAR_INT_ARRAY,			{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR, TRANSLATE_COND_SIZEOF_ARRAY}},
	{PT_VAR_FLOAT_ARRAY,		{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR, TRANSLATE_COND_SIZEOF_ARRAY}},
	{PT_VAR_TEXT_LABEL_ARRAY,	{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR, TRANSLATE_COND_SIZEOF_ARRAY}},
	{PT_VAR_STRING_ARRAY,		{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR, TRANSLATE_COND_SIZEOF_ARRAY}},
	{PT_LVAR_INT_ARRAY,			{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR, TRANSLATE_COND_SIZEOF_ARRAY}},
	{PT_LVAR_FLOAT_ARRAY,		{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR, TRANSLATE_COND_SIZEOF_ARRAY}},
	{PT_LVAR_TEXT_LABEL_ARRAY,	{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR, TRANSLATE_COND_SIZEOF_ARRAY}},
	{PT_LVAR_STRING_ARRAY,		{TRANSLATE_COND_SIZEOF_VAR, TRANSLATE_COND_SIZEOF_INDEXVAR, TRANSLATE_COND_SIZEOF_ARRAY}},
};

void CSyntax::AddType(TypeIndex t)
{
	if(s_pTypes[t.m_nIdx])
		throw(SCRambl.BuildText(SCRambl.GetText("SYNTAX", "M100"), NULL, 0, "%s", s_pTypes[t.m_nIdx]->GetName()));

	// Add it, list it, map it
	auto pType = new CType(t.m_nIdx);
	s_TypeList.Add(s_pTypes[t.m_nIdx] = pType);
	s_TypeMap.Add(pType->GetHash(), pType);
}
void CSyntax::AddExtendedType(ExtendedTypeIndex t)
{
	if(t.m_eIdx == ET_NONE) return;
	int idx = t.m_wIdx - 1;
	if(s_pExtendedTypes[idx])
		throw(SCRambl.BuildText(SCRambl.GetText("SYNTAX", "M100"), NULL, 0, "%s", s_pTypes[t.m_wIdx]->GetName()));
	
	if(auto pType = s_pTypes[s_pExtendedTypeNames[idx].m_nTypeIdx.m_nIdx])
	{
		// Add it, list it, map it
		auto pExType = new CExtendedType(t, s_pTypes[s_pExtendedTypeNames[idx].m_nTypeIdx.m_nIdx]);
		s_TypeList.Add((s_pExtendedTypes[idx] = pExType));
		s_TypeMap.Add(pExType->GetHash(), pExType);
	}
	else throw(SCRambl.BuildText(SCRambl.GetText("SYNTAX", "M101"), NULL, 0, "%s", s_pTypes[idx]->GetName()));
}
void CSyntax::AddExtendedType(TypeIndex basic_type, const char * szId, const char * szName, eTokenType token_type)
{
	if(auto pType = s_pTypes[basic_type.m_nIdx])
	{
		// Add it, list it, map it
		auto pExType = new CExtendedType(MAX_BUILT_IN_EXTENDED_TYPES + s_nNumExtendedTypes++, szId, pType, szName, token_type);
		s_TypeList.Add(pExType);
		s_TypeMap.Add(pExType->GetHash(), pExType);
	}
	else throw(SCRambl.BuildText(SCRambl.GetText("SYNTAX", "M101"), NULL, 0, "%s", szName));
}
void CSyntax::AddEnum(const char *szId, const CEnum *pEnum)
{
	auto pExType = new CExtendedType(szId, s_pTypes[TYPE_INT], pEnum);
	s_TypeMap.Add(pEnum->GetHash(), pExType);
	s_TypeList.Add(pExType);
}

// Access to all types, even user-defined
const CTypeBase *	CSyntax::GetTypeByID(const char *szVal)
{
	char id[12];
	int i = 0;
	while(GetTypeFlagByIdentifier(*szVal)) ++szVal;
	for(; IsAlphanumeric(szVal[i]); ++i);
	++i;
	if(i > sizeof(id)) i = sizeof(id);
	szncpy(id, szVal, i);
	for(auto pLink = s_TypeList.Begin(); pLink != s_TypeList.Bad(); ++pLink)
	{
		if(pLink->IsID(id)) return *pLink;
	}
	return nullptr;
}

// Get any type by it's name
const CTypeBase *	CSyntax::GetTypeByName(const char *szName)
{
	DWORD dwHash;
	if(const char * pStr = strchr(szName, ':'))
		dwHash = GenerateHash(szName, pStr - szName);
	else
		dwHash = GenerateHash(szName);
	auto pType = s_TypeMap.Get(dwHash);
	while(pType && !pType->IsNamed(szName)) pType = s_TypeMap.Next();
	return pType;
}

// Guess wut this duz?
void CSyntax::LoadDefaultTypes()
{
	if(!s_bDefaultsLoaded)
	{
		// Set defaults
		for(TypeIndex ti(TYPE_NONE); ti.m_nIdx < MAX_TYPES; ++ti.m_nIdx)
			AddType(ti);
		for(ExtendedTypeIndex ti(ET_FIRST); ti.m_wIdx < NUM_BUILT_IN_EXTENDED_TYPES; ++ti.m_wIdx)
			AddExtendedType(ti);
		
		s_bDefaultsLoaded = true;
	}
}

// Get subtoken data
bool CSyntax::GetArrayIndexAndTokenize(char *szVarString, int &nArrayIdxOut, char *&szVarName)
{
	nArrayIdxOut = 0;
	szVarName = nullptr;

	if(char *astr = strchr(szVarString, '['))
	{
		if(char *bstr = strrchr(astr, ']'))
		{
			*astr++ = '\0';
			*bstr = '\0';

			if(*astr == '[' && (bstr = strrchr(astr, ']')))
				*bstr = '\0';

			switch(CParser::GetTokenData(*astr == '[' ? astr++ : astr))
			{
			case TOKEN_VALUE:
				if(IsStringInt(astr)) nArrayIdxOut = StringToInt(astr);
				else if(IsStringInt(CParser::s_pCurrentToken))
					nArrayIdxOut = StringToInt(CParser::s_pCurrentToken);
				break;
			default:
				szVarName = astr;
				break;
			}
		}
		return true;
	}
	return false;
}

// Load types.def
void CSyntax::LoadTypes(const char *szFilePath)
{
	// Load custom definitions
	if(FILE * hFile = OpenFile(szFilePath, "rt"))
	{
		while(char *szLine = GetConfigLine(hFile))
		{
			char *	name = strtok(szLine, " \t\n\r");
			if(!name) continue;
			char *	cond = strchr(name, '(');
			char *	arri = strchr(name, '[');

			if(cond) *cond++ = '\0';
			bool bIsArray = arri != nullptr;
			if(arri) *arri++ = '\0';

			auto pType = s_TypeMap.Get(GenerateHash(name));
			//if(pType) pType = s_pTypes[CSyntax::GetBasicTypeIndex(pType->GetBasicType())];

			if(pType)
			{
				name = arri;
				if(arri && (arri = strchr(arri, ']'))) *arri++ = '\0';
				
				auto pTranslation = new CTranslation(pType, name && *name ? s_TypeMap.Get(GenerateHash(name)) : nullptr);

				name = cond;
				if(cond && (cond = strchr(cond, ')'))) *cond++ = '\0';

				if(name)
				{
					int i = 0;
					while(*name)
					{
						while(IsSpace(*name)) ++name;
						int size = 0;
						bool bConstSize = false;

						if(*name)
						{
							if(*name == '=')
							{
								bConstSize = true;
								++name;
							}
							if(IsStringInt(name)) size = StringToInt(name, name);
							else if(!strncmp(name, "NULL", sizeof("NULL")-1)) name += sizeof("NULL");
							else if(!strncmp(name, "INT8", sizeof("INT8")-1))
							{
								size = DT_INT8;
								name += sizeof("INT8");
							}
							else if(!strncmp(name, "INT16", sizeof("INT16")-1))
							{
								size = DT_INT16;
								name += sizeof("INT16");
							}
							else if(!strncmp(name, "INT24", sizeof("INT24")-1))
							{
								size = DT_INT24;
								name += sizeof("INT24");
							}
							else if(!strncmp(name, "INT32", sizeof("INT32")-1))
							{
								size = DT_INT32;
								name += sizeof("INT32");
							}
							else if(!strncmp(name, "FLOAT8", sizeof("FLOAT8")-1))
							{
								size = DT_FLOAT8;
								name += sizeof("FLOAT8");
							}
							else if(!strncmp(name, "FLOAT16", sizeof("FLOAT16")-1))
							{
								size = DT_FLOAT16;
								name += sizeof("FLOAT16");
							}
							else if(!strncmp(name, "FLOAT24", sizeof("FLOAT24")-1))
							{
								size = DT_FLOAT24;
								name += sizeof("FLOAT24");
							}
							else if(!strncmp(name, "FLOAT32", sizeof("FLOAT32")-1))
							{
								size = DT_FLOAT32;
								name += sizeof("FLOAT32");
							}
							else if(!strncmp(name, "FIXED16", sizeof("FIXED16")-1))
							{
								size = DT_FIXED16;
								name += sizeof("FIXED16");
							}
							else
							{
								THROW("Error during parsing '%s'", name);
								size = -1;
								while(*name != ',' && !IsSpace(*name)) ++name;
							}
						
							while(*name && IsSpace(*name)) ++name;
							if(*name == ',') ++name;
						}
						else size = -1;
						
						if(size != -1)
						{
							if(bIsArray && !pType->IsAnyArray())
							{
								int type = pType->GetType();
								type |= PT_ARRAY;
								int nIdx = CSyntax::GetBasicTypeIndex((PType)type);
								if(nIdx != TYPE_NONE) pType = s_pTypes[nIdx];
								else throw(SCRambl.BuildText(SCRambl.GetText("SYNTAX", "M102"), NULL, 0, "%s", pType->GetName()));
								pTranslation->PromoteBySubScript(pType);
							}
							pTranslation->AddCondition(s_TypeConditions[CSyntax::GetBasicTypeIndex(pType->GetType())].m_eConditions[i], size, bConstSize);
						}
						++i;
					}
				}
				
				int nTranslationSize = 0;
				while((name && *name == '@') || (name = strtok(nullptr, " \t\n\r")))
				{
					bool bIsNeg;
					if(*name == '-')
					{
						bIsNeg = true;
						++name;
					}
					else bIsNeg = false;

					if(*name == '@')
					{
						if(IsStringInt(++name))
						{
							int idx = StringToInt(name);
							if(pType->IsAnyArray())
								--idx;
							if(idx <= 0)
							{
								eTranslateOperand operand;
								if(pType->IsAnyArray()) operand = idx >= 0 ? TRANSLATE_OPERAND_IDXVAR : TRANSLATE_OPERAND_VAR;
								else operand = pType->IsAnyVar() ? TRANSLATE_OPERAND_VAR : TRANSLATE_OPERAND_VAL;
								pTranslation->AddElement(TRANSLATE_ELEM_OPERAND, operand);
							}
							else pTranslation->AddElement(TRANSLATE_ELEM_COND, pTranslation->GetCondition(--idx));
						}
					}
					else if(IsStringInt(name)) pTranslation->AddElement(TRANSLATE_ELEM_VAL, bIsNeg ? -StringToInt(name) : StringToInt(name));
				}

				pType->AddTranslation(pTranslation);
			}
			else if(!cond && !arri)
			{
				char * id = name;
				name = strtok(nullptr, " \t");
				char * stdn = name ? strchr(name, '(') : nullptr;
				cond = stdn ? strchr(stdn, ')') : nullptr;
				if(cond)
				{
					*cond++ = '\0';
					*stdn++ = '\0';
					pType = s_TypeMap.Get(GenerateHash(stdn));
					if(pType && !s_TypeMap.Get(GenerateHash(name)))
					{
						char * ttype = strtok(nullptr, " \t\n\r");
						eTokenType typetok = TOKEN_NONE;
						if(ttype && *ttype)
						{
							if(!strcmp(ttype, "CONSTANT")) typetok = TOKEN_CONSTANT;
							else if(!strcmp(ttype, "LABEL")) typetok = TOKEN_LABEL;
							else if(!strcmp(ttype, "MODEL")) typetok = TOKEN_MODEL;
							else if(!strcmp(ttype, "STRING")) typetok = TOKEN_STRING;
							else if(!strcmp(ttype, "VALUE")) typetok = TOKEN_VALUE;
							else if(!strcmp(ttype, "VAR")) typetok = TOKEN_VAR;
						}

						AddExtendedType(pType->Standardise()->GetInternalID(), id, name, typetok);
					}
				}
			}
		}
		CloseFile(hFile);
	}
}
void CSyntax::LoadScmInfo(const char *szFilePath)
{
	if(FILE *hFile = OpenFile(szFilePath, "rt"))
	{
		while(char *pLine = GetConfigLine(hFile))
		{
			char *	name = strtok(pLine, " \t,"),
				 *	value = strtok(NULL, " \t,");

			if(name && value)
			{
				if(!strncmp(name, "SCRIPT_", 7))
				{
					name += 7;

					for(int i=0; i<SCRIPT_MAX_PARSED_OPCODES; i++)
					{
						if(!strcmp(s_pParseOpcodeArray[i].szName, name))
						{
							DWORD opcode = StringToInt(value);
							if(auto pOpcode = COpcodes::Get(opcode))
							{
								pOpcode->SetParseFunc(s_pParseOpcodeArray[i].nFuncID);
								COpcodes::RegisterForParsing(s_pParseOpcodeArray[i].nFuncID, pOpcode);
							}
							break;
						}
					}
				}
				else
				{
					for(int i=0; i < sizeof(s_pDefinitions) && s_pDefinitions[i].szName; i++)
					{
						if(!strcmp(s_pDefinitions[i].szName, name))
						{
							s_pDefinitions[i].bUsed = true;
							s_pDefinitions[i].nValue.i = StringToInt(value);
							break;
						}
					}
				}
			}
		}
		CloseFile(hFile);
	}
}
void CSyntax::LoadScrInfo(const char *szFilePath)
{
	if(FILE *hFile = OpenFile(szFilePath, "rt"))
	{
		while(char *pLine = GetConfigLine(hFile))
		{
			char * str;
			for(str = pLine + 1; *str && str[-1]; str++)
			{
				if(*str == '=') *str = '\0';
			}

			if(*str && IsStringInt(pLine))
			{
				int value = StringToInt(pLine);
				strncpy(s_pConstructs[value].szName, str, sizeof(s_pConstructs[value].szName));
			}
		}
		CloseFile(hFile);
	}
}